package com.lin.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lin.entity.Chapter;
import com.lin.entity.Course;
import com.lin.entity.Video;
import com.lin.entity.vo.course.CourseInfoVo;
import com.lin.entity.vo.front.CourseConditionVo;
import com.lin.entity.vo.front.CourseFrontInfoVo;
import com.lin.exception.LinException;
import com.lin.mapper.CourseMapper;
import com.lin.service.ChapterService;
import com.lin.service.CourseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lin.service.VideoService;
import com.lin.utils.ConstantPropertiesUtils;
import com.lin.utils.ResultCode;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 课程 服务实现类
 * </p>
 *
 * @author 霖霖
 * @since 2022-12-23
 */
@Service
public class CourseServiceImp extends ServiceImpl<CourseMapper, Course> implements CourseService {
    @Autowired
    private ChapterService chapterService;
    @Autowired
    private VideoService videoService;

    @Override
    public String saveCover(MultipartFile file) throws IOException {
        // Endpoint 服务区，以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = ConstantPropertiesUtils.END_POINT;
        // 阿里云账号AccessKey拥有所有API的访问权限。
        String accessKeyId = ConstantPropertiesUtils.KEY_ID;
        String accessKeySecret = ConstantPropertiesUtils.KEY_SECRET;
        //桶名
        String bucketName = ConstantPropertiesUtils.BUCKET_NAME;

        // 填写本地文件的完整路径，例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            InputStream inputStream = file.getInputStream();
            StringBuilder url = new StringBuilder();
            String fileName = file.getOriginalFilename();
            //修改文件名
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //文件分类
            String datePath = new DateTime().toString("yyyy/MM/dd");
            url.append(datePath).append("/").append(uuid).append(fileName);
            // 创建PutObject请求。1桶名，2文件路径，3文件输入流
            ossClient.putObject(bucketName, url.toString(), inputStream);
            //拼接存储使用的url
            url.insert(0, "https://" + ConstantPropertiesUtils.BUCKET_NAME + "." + ConstantPropertiesUtils.END_POINT + "/");
            return url.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    @Override
    public CourseInfoVo getCourseInfo(String courseId) {
        return baseMapper.selectCourseInfoById(courseId);
    }

    @Override
    public IPage<CourseInfoVo> getCourseInfoVos(IPage<CourseInfoVo> page, String title, String startTime, String endTime, String order, Byte type,String teacherId) {
        return baseMapper.selectCourseInfoVo(page, teacherId, title, startTime, endTime, order, type);
    }

    @Override
    @Transactional
    public boolean removeCourse(String courseId) {
        if (videoService.removeVideoBatch(courseId)) {
            QueryWrapper<Chapter> chapterQueryWrapper = new QueryWrapper<>();
            chapterQueryWrapper.eq("course_id", courseId);
            if (chapterService.remove(chapterQueryWrapper)) {
                return baseMapper.deleteById(courseId) > 0;
            }
        }
        return false;
    }

    @Override
    public Map<String, Object> getLiveCourseInfoVos(IPage<CourseInfoVo> page, String title, String startTime, String endTime, String order, Byte type, String teacherId) {
        baseMapper.selectLiveCourseInfoVo((Page<CourseInfoVo>) page, teacherId, title, startTime, endTime, order, type);
        return null;
    }

    @Override
    @Transactional
    public boolean saveLiveVideo(Video video) {
        dateSort(video);
        QueryWrapper<Video> videoQueryWrapper = new QueryWrapper<>();
        videoQueryWrapper.select("course_id");
        videoQueryWrapper.eq("course_id",video.getCourseId());
        QueryWrapper<Course> courseQueryWrapper = new QueryWrapper<>();
        courseQueryWrapper.eq("id",video.getCourseId());
        courseQueryWrapper.select("lesson_num");
        Course course = baseMapper.selectOne(courseQueryWrapper);
        if (videoService.count(videoQueryWrapper)>=course.getLessonNum())
            throw new LinException(ResultCode.ERROR,"超过预定义课时数"+course.getLessonNum()+"课时,请修改后添加");

        videoQueryWrapper.eq("chapter_id", video.getChapterId());
        videoQueryWrapper.eq("sort", video.getSort());
        long count = videoService.count(videoQueryWrapper);
        if (count > 0) {
            throw new LinException(ResultCode.ERROR, "第" + video.getSort() + "课时已存在，请修改后添加");
        }
        int flag = -1;
        flag = updateCourseStartTime(video, flag);
        return videoService.save(video) && (flag == -1 || flag > 0);
    }

    @Override
    @Transactional
    public boolean updateLiveVideo(Video video) {
        QueryWrapper<Video> videoQueryWrapper = new QueryWrapper<>();
        videoQueryWrapper.eq("sort", video.getSort());
        videoQueryWrapper.eq("chapter_id", video.getChapterId());
        videoQueryWrapper.ne("id", video.getId());
        long count = videoService.count(videoQueryWrapper);
        if (count > 0) {
            throw new LinException(ResultCode.SORT_EXISTS, "第" + video.getSort() + "课时已存在" + "是否交换课时顺序");
        }
        int flag = -1;
        flag = updateCourseStartTime(video, flag);
        return (flag == -1 || flag > 0) && videoService.updateById(video);
    }

    private int updateCourseStartTime(Video video, int flag) {
        Chapter chapter = chapterService.getById(video.getChapterId());
        if (video.getSort() == 1 && chapter.getSort() == 1) {
            flag = 0;
            Course course = new Course();
            course.setId(video.getCourseId());
            course.setStartTime(video.getStartTime());
            flag = baseMapper.updateById(course);
        }
        return flag;
    }

    @Override
    @Transactional
    public boolean swapUpdateLiveVideo(Video video) {

        //获取同新video相同的sort的video
        QueryWrapper<Video> videoQueryWrapper = new QueryWrapper<>();
        videoQueryWrapper.eq("sort", video.getSort());
        videoQueryWrapper.eq("chapter_id", video.getChapterId());
        videoQueryWrapper.eq("course_id", video.getCourseId());
        videoQueryWrapper.select("id", "sort", "start_time");
        Video conflictVideo = videoService.getOne(videoQueryWrapper);
        return videoService.swapUpdateVideo(video, conflictVideo);

    }

    @Override
    public boolean updateLiveVideoStartTime(Video video) {
        dateSort(video);

        QueryWrapper<Chapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq("id", video.getChapterId());
        chapterQueryWrapper.select("sort");
        Chapter chapter = chapterService.getOne(chapterQueryWrapper);

        int flag = 0;
        if (chapter.getSort() == 1 && video.getSort() == 1) {
            Course course = new Course();
            course.setId(video.getCourseId());
            course.setStartTime(video.getStartTime());
            flag = baseMapper.updateById(course);
            return flag > 0 && videoService.updateById(video);
        }
        return videoService.updateById(video);
    }

    @Override
    @Transactional
    public boolean removeLiveCourse(String courseId) {
        QueryWrapper<Video> videoQueryWrapper = new QueryWrapper<>();
        videoQueryWrapper.eq("course_id", courseId);

        QueryWrapper<Chapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq("course_id", courseId);

        videoService.remove(videoQueryWrapper);
        chapterService.remove(chapterQueryWrapper);
        return baseMapper.deleteById(courseId)>0;
    }

    @Override
    public CourseFrontInfoVo getFrontCourseInfo(String courseId) {
        return baseMapper.selectFrontCourseInfoVo(courseId);
    }

    @Override
    public JSONObject getCourseInfoByCondition(Page<Course> coursePage, CourseConditionVo courseConditionVo, Byte type) {
        LambdaQueryWrapper<Course> courseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        courseLambdaQueryWrapper.eq(StringUtils.isNotBlank(courseConditionVo.getSubjectParentId()),Course::getSubjectParentId,courseConditionVo.getSubjectParentId());
        courseLambdaQueryWrapper.eq(StringUtils.isNotBlank(courseConditionVo.getSubjectId()),Course::getSubjectId,courseConditionVo.getSubjectId());
        courseLambdaQueryWrapper.eq(Course::getType,type);
        courseLambdaQueryWrapper.eq(courseConditionVo.getAge()!=null,Course::getAge,courseConditionVo.getAge());
        //根据关注的排序
        courseLambdaQueryWrapper.orderByDesc(StringUtils.isNotBlank(courseConditionVo.getBuyCountSort()),Course::getBuyCount);
        courseLambdaQueryWrapper.orderByDesc(StringUtils.isNotBlank(courseConditionVo.getGmtCreateSort()),Course::getGmtCreate);
        courseLambdaQueryWrapper.orderByDesc(StringUtils.isNotBlank(courseConditionVo.getPriceSort()),Course::getPrice);
        baseMapper.selectPage(coursePage,courseLambdaQueryWrapper);

        boolean hasNext=true;
        boolean hasPrevious=true;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("items",coursePage.getRecords());
        jsonObject.put("current",coursePage.getCurrent());
        jsonObject.put("pages",coursePage.getPages());
        jsonObject.put("size",coursePage.getSize());
        jsonObject.put("total",coursePage.getTotal());
        if (coursePage.getCurrent()<=1)
            hasPrevious=false;
        if (coursePage.getCurrent()>=coursePage.getPages())
            hasNext=false;
        jsonObject.put("hasNext",hasNext);
        jsonObject.put("hasPrevious",hasPrevious);

        return jsonObject;
    }

    @Override
    public Long statisticsCount(LocalDateTime yesterdays) {
        return baseMapper.selectStatisticCount(yesterdays);
    }


    void dateSort(Video video) {
        if (video.getSort() != 1) {
            LocalDateTime preStartTime = videoService.getPreVideo(video);
            if (preStartTime.isAfter(video.getStartTime()))
                throw new LinException(ResultCode.START_TIME_ERROR, "课程开课时间早于上一课时开课时间，请先修改上一课开课时间");
        }
        LocalDateTime nextStartTime = videoService.getNextVideo(video);
        if (nextStartTime != null && nextStartTime.isBefore(video.getStartTime()))
            throw new LinException(ResultCode.START_TIME_ERROR, "课程开课时间晚于于下一课时开课时间，请先修改下一课开课时间");
    }
}
